package com.gmrz.uap.cfg;

import com.gmrz.uap.authenticators.AuthenticatorsController;
import com.gmrz.uap.cache.AmmsCacheUtil;
import com.gmrz.uap.common.AuthInterceptor;
import com.gmrz.uap.common.DB2Dialect;
import com.gmrz.uap.common.HostFilterInterceptor;
import com.gmrz.uap.common.db.DataSourceShardingConst;
import com.gmrz.uap.common.db.DataSourceShardingFactory;
import com.gmrz.uap.datastatistics.DataStatisticsController;
import com.gmrz.uap.dict.DictController;
import com.gmrz.uap.equipment.EquipmentController;
import com.gmrz.uap.fidohislog.FidoHisLogController;
import com.gmrz.uap.fidolog.FidoLogController;
import com.gmrz.uap.globalist.GlobalBlackWhiteListController;
import com.gmrz.uap.jedis.JedisController;
import com.gmrz.uap.jfinal.interceptor.SessionManagerInterceptor;
import com.gmrz.uap.jfinal.plugin.QuartzPlugin;
import com.gmrz.uap.jfinal.plugin.UAPQuartzPlugin;
import com.gmrz.uap.model.*;
import com.gmrz.uap.operlog.OperLogController;
import com.gmrz.uap.authmetadata.AuthMetadataController;
import com.gmrz.uap.policy.PolicyController;
import com.gmrz.uap.resource.ResourceController;
import com.gmrz.uap.role.RoleController;
import com.gmrz.uap.serviceplugin.ServicePluginController;
import com.gmrz.uap.tenant.TenantController;
import com.gmrz.uap.tenantconfig.TenantConfigController;
import com.gmrz.uap.facet.FacetController;
import com.gmrz.uap.uasconfig.UasConfigConst;
import com.gmrz.uap.uasconfig.UasConfigContentService;
import com.gmrz.uap.uasconfig.UasConfigController;
import com.gmrz.uap.user.UserController;

import com.gmrz.uap.whitelist.WhiteListController;
import com.jfinal.config.*;
import com.jfinal.core.Const;
import com.jfinal.ext.handler.ContextPathHandler;
import com.jfinal.i18n.I18nInterceptor;
import com.jfinal.json.MixedJsonFactory;
import com.jfinal.kit.Prop;
import com.jfinal.kit.PropKit;
import com.jfinal.kit.ReflectKit;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.activerecord.CaseInsensitiveContainerFactory;
import com.jfinal.plugin.activerecord.dialect.MysqlDialect;
import com.jfinal.plugin.activerecord.dialect.OracleDialect;
import com.jfinal.plugin.ehcache.CacheKit;
import com.jfinal.plugin.ehcache.EhCachePlugin;
import com.jfinal.template.Engine;
import org.apache.log4j.Logger;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.exceptions.JedisConnectionException;

import javax.sql.DataSource;

public class AppConfig extends JFinalConfig {

    private static final Logger LOG = Logger.getLogger(AppConfig.class);

    private static Prop p = loadConfig();

    private static Prop loadConfig() {
        try {
            // 优先加载生产环境配置文件
            return PropKit.use("application.properties");
        } catch (Exception e) {
            // 找不到生产环境配置文件，再去找开发环境配置文件
            return PropKit.use("application.properties");
        }
    }

    public void configConstant(Constants me) {
        me.setDevMode(p.getBoolean("devMode", false));
        me.setMaxPostSize(100 * Const.DEFAULT_MAX_POST_SIZE);
        me.setI18nDefaultLocale(SystemConst.SYSTEM_DEFAULT_LOCALE);
        me.setJsonFactory(MixedJsonFactory.me());
        me.setError403View("/403.html");
        me.setError404View("/404.html");
        me.setError500View("/500.html");
    }

    public void configRoute(Routes me) {

        me.add("/", SystemController.class);
        me.add("/user", UserController.class);//管理員管理
        me.add("/resource", ResourceController.class);//資源管理
        me.add("/role", RoleController.class);//角色管理
        me.add("/tenant", TenantController.class);//租户管理
        me.add("/tenantConfig", TenantConfigController.class);//租户配置管理
        me.add("/fidoLog", FidoLogController.class);//业务日志
        me.add("/operLog", OperLogController.class);//操作日志
        me.add("/fidohisLog", FidoHisLogController.class);//业务历史日志


        me.add("/dict", DictController.class);//数据字典
        me.add("/whiteList", WhiteListController.class);//白名单管理

        me.add("/facet", FacetController.class);//应用管理
        me.add("/uasConfig", UasConfigController.class);//系统配置,redis配置
        me.add("/authMetadata", AuthMetadataController.class);//元数据管理
        me.add("/policy", PolicyController.class);//策略管理


        me.add("/authenticators", AuthenticatorsController.class);//注册信息

        me.add("/servicePlugin", ServicePluginController.class);//插件管理

        me.add("/equipment", EquipmentController.class);//设备管理
        me.add("/globalBlackWhiteList", GlobalBlackWhiteListController.class);//全局黑白名单管理
        me.add("/dataStatistics", DataStatisticsController.class);//日数据统计

        me.add("/jedis", JedisController.class);//REDIS管理


    }

    public void configEngine(Engine me) {
        me.setBaseTemplatePath(SystemConst.getWebRootUrl() + "/WEB-INF/_views");
        me.setDevMode(p.getBoolean("engineDevMode", false));
        me.addSharedFunction("/common/layout.html");
        me.addSharedFunction("/common/embed_layout.html");

        me.addSharedMethod(new com.jfinal.kit.StrKit());
        me.addSharedObject("SystemConst", new SystemConst());

        LOG.info("模板路径 ==> " + me.getBaseTemplatePath());
    }

    public void configPlugin(Plugins me) {
        DataSource dataSource = null;

        DataSourceShardingFactory dataSourceShardingFactory;
        try {
            dataSourceShardingFactory = (DataSourceShardingFactory) ReflectKit.newInstance(Class.forName(DataSourceShardingConst.getConfigInfo(DataSourceShardingConst.DATASOURCE_IMPL_CLASS)));
            dataSource = dataSourceShardingFactory.getInstance();
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
        }

        // 配置非日志数据源插件
        ActiveRecordPlugin arp = new ActiveRecordPlugin(dataSource);


        // 配置属性名(字段名)大小写不敏感容器工厂
        arp.setContainerFactory(new CaseInsensitiveContainerFactory(true));

        // 根据数据源获取所连接的数据库类型
        String dbType = SystemConst.getDbTypeByDatabase(dataSource, "fidoDB");
        // 将获取到数据库类型赋值给静态变量--DB_TYPE, 用于定时日志删除功能中判断所连接数据库
        SystemConst.DB_TYPE = dbType;

        String sqlFilePath = null;
        if (dbType.equals(SystemConst.DB_TYPE_MYSQL)) {
            sqlFilePath = "/WEB-INF/database/mysql";
            arp.setDialect(new MysqlDialect());
        } else if (dbType.equals(SystemConst.DB_TYPE_ORACLE)) {
            sqlFilePath = "/WEB-INF/database/oracle";
            arp.setDialect(new OracleDialect());
        } else if (dbType.equals(SystemConst.DB_TYPE_DB2)) {
            sqlFilePath = "/WEB-INF/database/db2";
            arp.setDialect(new DB2Dialect());
        } else {
            LOG.error("database type ==> " + dbType + " is not supply");
        }
        sqlFilePath = SystemConst.getWebRootUrl() + sqlFilePath;
        LOG.info("sql template path ==> " + sqlFilePath);
        arp.setBaseSqlTemplatePath(sqlFilePath);

        // 添加SQL文件
        _SQLKit.mapping(arp);
        // 控制台是否打印显示SQL
        arp.setShowSql(SystemConst.getDevMode());
        // 所有配置在 MappingKit，将数据库表与实体类进行映射
        _MappingKit.mapping(arp);
        me.add(arp);

        //uaslog日志数据库连接
        DataSource fidoLogDataSource = null;
        DataSourceShardingFactory dataSourceLogShardingFactory;
        try {
            dataSourceLogShardingFactory = (DataSourceShardingFactory) ReflectKit.newInstance(Class.forName(DataSourceShardingConst.getConfigInfo(DataSourceShardingConst.DATASOURCE_LOG_IMPL_CLASS)));
            fidoLogDataSource = dataSourceLogShardingFactory.getInstance();
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
        }
        // 配置日志数据源插件
        ActiveRecordPlugin fidoLogActiveRecordPlugin = new ActiveRecordPlugin(SystemConst.DB_FIDOLOG_DATASOURCE, fidoLogDataSource);
        fidoLogActiveRecordPlugin.setShowSql(SystemConst.getDevMode());//是否显示执行的语句

        fidoLogActiveRecordPlugin.setContainerFactory(new CaseInsensitiveContainerFactory(true));//配置属性名(字段名)大小写不敏感容器工厂

        fidoLogActiveRecordPlugin.setShowSql(SystemConst.getDevMode());
        // addMapping 方法建立了数据库表名到Model的映射关系。
        fidoLogActiveRecordPlugin.addMapping("t_fido_log", "fl_id", FidoLog.class);
        fidoLogActiveRecordPlugin.addMapping("t_oper_log", "opr_id", OperLog.class);

        dbType = SystemConst.getDbTypeByDatabase(fidoLogDataSource, "fidoLogDB");
        if (dbType.equals(SystemConst.DB_TYPE_MYSQL)) {
            sqlFilePath = "/WEB-INF/database/mysql";
            fidoLogActiveRecordPlugin.setDialect(new MysqlDialect());
        } else if (dbType.equals(SystemConst.DB_TYPE_ORACLE)) {
            sqlFilePath = "/WEB-INF/database/oracle";
            fidoLogActiveRecordPlugin.setDialect(new OracleDialect());
        } else if (dbType.equals(SystemConst.DB_TYPE_DB2)) {
            sqlFilePath = "/WEB-INF/database/db2";
            fidoLogActiveRecordPlugin.setDialect(new DB2Dialect());
        } else {
            LOG.error("log database type ==> " + dbType + " is not supply");
        }

        sqlFilePath = SystemConst.getWebRootUrl() + sqlFilePath;
        LOG.info("log sql template path ==> " + sqlFilePath);
        fidoLogActiveRecordPlugin.setBaseSqlTemplatePath(sqlFilePath);

        fidoLogActiveRecordPlugin.addSqlTemplate("fido_log.sql");
        fidoLogActiveRecordPlugin.addSqlTemplate("oper_log.sql");

        me.add(fidoLogActiveRecordPlugin);

        if (p.getBoolean("task.cluster")) {
            me.add(new QuartzPlugin());
        } else {
            me.add(new UAPQuartzPlugin("/job.properties"));
        }

        me.add(new EhCachePlugin());

    }

    public void configInterceptor(Interceptors me) {
        me.addGlobalActionInterceptor(new HostFilterInterceptor());//访问地址过滤
        me.add(new I18nInterceptor());//国际化
        me.addGlobalActionInterceptor(new AuthInterceptor());//管理员登录拦截
        me.addGlobalActionInterceptor(new SessionManagerInterceptor());//会话
    }

    public void configHandler(Handlers me) {
        me.add(new ContextPathHandler("ctx"));//ContextPath
    }

    /**
     * 系统启动完成之后回调使用
     * 完成系统配置数据的缓存存储，jfinal自带的缓存
     */
    public void afterJFinalStart() {
        // 将系统配置数据放到jfinal的缓存中
        UasConfigContentService.me.initUasConfigToCache();

        try {
            // 这里是进行redis缓存的初始化，并进行测试看看redis缓存是否可以使用
            AmmsCacheUtil.getCacheStoreService().set("connect_test", "The test will be able to connect to Redis");
        } catch (JedisConnectionException e) {
            // 如果redis缓存不可用，则启动本地缓存
            LOG.error("Unable to connect to Redis, change to use local cache");
            CacheKit.put(UasConfigConst.UASCONIFG_CACHE, UasConfigConst.UAFCHALLENGESTORECLASSNAME, AmmsCacheUtil.CHALLENGESTORESERVICEDEFAULTIMPL);
        }
    }
}

